#include "oled_GME12864.h"
#include "stdlib.h"
#include "string.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "kp_base_type.h" 
#include <stdint.h>
#include "app_oled.h"

// #define OLED_NAME_GPIO_13  0//13
// #define OLED_NAME_GPIO_14  1//14
// #define OLED_IIC_IDX_0     1//0
// #define OLED_IIC_BAUDRATE  200000
// #define SSD1306_I2C_IDX     1//0
// #define SSD1306_I2C_ADDR    (0x3C <<1)

#define SSD1306_CTRL_CMD 0x00
#define SSD1306_CTRL_DATA 0x40
#define SSD1306_MASK_CONT (0x1<<7)



//定义I2C和SPI的宏
#define SSD1306_USE_IIC 1
#define SSD1306_USE_SPI 0

/* 配置ssd1306使用的协议*/
#define SSD1306_TRANS_PROTOCOL SSD1306_USE_IIC

//OLED显存总共分为8页
//每页8行，一行128个像素点
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127 (0~7)行	   
//[1]0 1 2 3 ... 127 (8~15)行	
//[2]0 1 2 3 ... 127 (16~23)行	
//[3]0 1 2 3 ... 127 (24~31)行	
//[4]0 1 2 3 ... 127 (32~39)行	
//[5]0 1 2 3 ... 127 (40~47)行	
//[6]0 1 2 3 ... 127 (48~55)行	
//[7]0 1 2 3 ... 127 (56~63)行			   

//数组每个bit存储OLED每个像素点的颜色值(1-亮(白色),0-灭(黑色))
//每个数组元素表示1列8个像素点，一共128列

static unsigned char OLED_buffer[1024] = { 0x00 };

/* oled IO初始化 */
void OLED_Init_GPIO(void)
{
    u32 ret = KP_ERR_SUCCESS;

    IoTGpioInit(OLED_NAME_GPIO_13);
    IoTGpioSetFunc(OLED_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA /*HI_IO_FUNC_GPIO_0_I2C1_SDA*/);
    // IoTGpioSetDir(OLED_NAME_GPIO_13, IOT_GPIO_DIR_OUT);

    IoTGpioInit(OLED_NAME_GPIO_14);
    IoTGpioSetFunc(OLED_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL /*HI_IO_FUNC_GPIO_1_I2C1_SCL*/);
    // IoTGpioSetDir(OLED_NAME_GPIO_14, IOT_GPIO_DIR_OUT);


    /* IIC初始化 */
    ret = IoTI2cInit(OLED_IIC_IDX_0, OLED_IIC_BAUDRATE);
    if (ret != KP_ERR_SUCCESS) {
        printf("IoTI2cInit failed :%#x \r\n", ret); 
        return;
    }

    /* IIC设置波特率 */
    ret = IoTI2cSetBaudrate(OLED_IIC_IDX_0, OLED_IIC_BAUDRATE);
    if (ret != KP_ERR_SUCCESS) {
        printf("IoTI2cSetBaudrate failed :%#x \r\n", ret); 
        return;
    }

    printf("SSD1306InitIO success \r\n");
}

void OLED_Reset(void) {
    /* for I2C - do nothing */
}

void HAL_Delay(uint32_t ms)
{
    uint32_t msPerTick = 1000 / osKernelGetTickFreq(); // 10ms
    if (ms >= msPerTick) {
        osDelay(ms / msPerTick);
    }

    uint32_t restMs = ms % msPerTick;
    if (restMs > 0) {
        usleep(restMs * 1000);
    }
}

uint32_t HAL_GetTick(void)
{
    uint32_t msPerTick = 1000 / osKernelGetTickFreq(); // 10ms
    uint32_t tickMs = osKernelGetTickCount() * msPerTick;

    uint32_t csPerMs = osKernelGetSysTimerFreq() / 1000; // 160K cycle/ms
    uint32_t csPerTick = csPerMs * msPerTick; // 1600K cycles/tick
    uint32_t restMs = osKernelGetSysTimerCount() % csPerTick / csPerMs;

    return tickMs + restMs;
}


// Send data
void OLED_WR_DATA(uint8_t *data,int data_len)
{
	uint8_t buff[WIDTH * 2] = { 0 };
    for (size_t i = 0; i < data_len; i++) {
        buff[i*2] = SSD1306_CTRL_DATA | SSD1306_MASK_CONT;
        buff[i*2+1] = data[i];
    }
    data[(data_len - 1) * 2] = SSD1306_CTRL_DATA;
    int ret = IoTI2cWrite(SSD1306_I2C_IDX, SSD1306_I2C_ADDR, buff, sizeof(buff));
	//printf("IoTI2cWrite ret = %d\n",ret);
}

//Send byte
void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
{
	if(cmd == OLED_DATA)//发送的是数据
	{
		// uint8_t data[SSD1306_WIDTH * 2] = {0};
    	// for (size_t i = 0; i < buff_size; i++) {
		// 	data[i*2] = SSD1306_CTRL_DATA | SSD1306_MASK_CONT;
		// 	data[i*2+1] = buffer[i];

		// 	uint8_t buffer[] = {regAddr, dat};
		// 	IoTI2cWrite(SSD1306_I2C_IDX, SSD1306_I2C_ADDR, buffer, sizeof(buffer));

    	// }
    	// data[(buff_size - 1) * 2] = SSD1306_CTRL_DATA;
	}
	else//发送的是命令
	{
		uint8_t buffer[] = {SSD1306_CTRL_CMD, dat};
    	int ret = IoTI2cWrite(SSD1306_I2C_IDX, SSD1306_I2C_ADDR, buffer, sizeof(buffer));
		//printf("IoTI2cWrite ret = %d\n",ret);
	}
}

// Screen object
// static SSD1306_t SSD1306;

/*******************************************************************
 * @name       :void OLED_Set_Pos(unsigned char x, unsigned char y) 
 * @date       :2018-08-27
 * @function   :Set coordinates in the OLED screen
 * @parameters :x:x coordinates
                y:y coordinates
 * @retvalue   :None
********************************************************************/
void OLED_Set_Pos(unsigned char x, unsigned char y) 
{
 	OLED_WR_Byte(YLevel+y/PAGE_SIZE,OLED_CMD);
	OLED_WR_Byte((((x+2)&0xf0)>>4)|0x10,OLED_CMD);
	OLED_WR_Byte(((x+2)&0x0f),OLED_CMD); 
}  

/*******************************************************************
 * @name       :void OLED_Display_On(void) 
 * @date       :2018-08-27
 * @function   :Turn on OLED display
 * @parameters :None
 * @retvalue   :None
********************************************************************/ 	  
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}

/*******************************************************************
 * @name       :void OLED_Display_Off(void)
 * @date       :2018-08-27
 * @function   :Turn off OLED display
 * @parameters :None
 * @retvalue   :None
********************************************************************/    
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}

/*******************************************************************
 * @name       :void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color)
 * @date       :2018-08-27
 * @function   :set the value of pixel to RAM
 * @parameters :x:the x coordinates of pixel
                y:the y coordinates of pixel
								color:the color value of the point
								      1-white
											0-black
 * @retvalue   :None
********************************************************************/ 
void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color)
{
	if(color)
	{
		OLED_buffer[(y/PAGE_SIZE)*WIDTH+x]|= (1<<(y%PAGE_SIZE))&0xff;
	}
	else
	{
		OLED_buffer[(y/PAGE_SIZE)*WIDTH+x]&= ~((1<<(y%PAGE_SIZE))&0xff);
	}
}		   			 

/*******************************************************************
 * @name       :void OLED_Display(void)
 * @date       :2018-08-27
 * @function   :Display in OLED screen
 * @parameters :None
 * @retvalue   :None
********************************************************************/  
void OLED_Display(void)
{
	u8 i,n;		    
	for(i=0;i<PAGE_SIZE;i++)  
	{  
		OLED_WR_Byte (YLevel+i,OLED_CMD);    //设置页地址（0~7）
		OLED_WR_Byte (XLevelL,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (XLevelH,OLED_CMD);      //设置显示位置—列高地址  
		// for(n=0;n<WIDTH;n++)
		// {
		// 	OLED_WR_Byte(OLED_buffer[i*WIDTH+n],OLED_DATA); 
		// }
		//更新显示
		OLED_WR_DATA(&OLED_buffer[i*WIDTH],WIDTH);
	}   
}

/*******************************************************************
 * @name       :void OLED_Clear(unsigned dat)  
 * @date       :2018-08-27
 * @function   :clear OLED screen
 * @parameters :dat:0-Display full black
                    1-Display full white
 * @retvalue   :None
********************************************************************/ 
void OLED_Clear(unsigned dat)  
{  
	if(dat)
	{
		memset(OLED_buffer,0xff,sizeof(OLED_buffer));
	}
	else
	{
		memset(OLED_buffer,0,sizeof(OLED_buffer));
	}
	OLED_Display();
}


/*******************************************************************
 * @name       :void OLED_Init(void)
 * @date       :2018-08-27
 * @function   :initialise OLED SH1106 control IC
 * @parameters :None
 * @retvalue   :None
********************************************************************/ 				    
void OLED_Init(void)
{
 	msleep(200); 
	OLED_Reset();     //复位OLED

/**************初始化SSD1306*****************/	
	OLED_WR_Byte(0xAE,OLED_CMD); /*display off*/
	OLED_WR_Byte(0x00,OLED_CMD); /*set lower column address*/
	OLED_WR_Byte(0x10,OLED_CMD); /*set higher column address*/
	OLED_WR_Byte(0x40,OLED_CMD); /*set display start line*/ 
	OLED_WR_Byte(0xB0,OLED_CMD); /*set page address*/
	OLED_WR_Byte(0x81,OLED_CMD); /*contract control*/ 
	OLED_WR_Byte(0xFF,OLED_CMD); /*128*/
	OLED_WR_Byte(0xA1,OLED_CMD); /*set segment remap*/ 
	OLED_WR_Byte(0xA6,OLED_CMD); /*normal / reverse*/
	OLED_WR_Byte(0xA8,OLED_CMD); /*multiplex ratio*/ 
	OLED_WR_Byte(0x3F,OLED_CMD); /*duty = 1/64*/
	OLED_WR_Byte(0xC8,OLED_CMD); /*Com scan direction*/
	OLED_WR_Byte(0xD3,OLED_CMD); /*set display offset*/ 
	OLED_WR_Byte(0x00,OLED_CMD);
	OLED_WR_Byte(0xD5,OLED_CMD); /*set osc division*/ 
	OLED_WR_Byte(0x80,OLED_CMD);
	OLED_WR_Byte(0xD9,OLED_CMD); /*set pre-charge period*/ 
	OLED_WR_Byte(0XF1,OLED_CMD);
	OLED_WR_Byte(0xDA,OLED_CMD); /*set COM pins*/ 
	OLED_WR_Byte(0x12,OLED_CMD);
	OLED_WR_Byte(0xDB,OLED_CMD); /*set vcomh*/ 
	OLED_WR_Byte(0x30,OLED_CMD);
	OLED_WR_Byte(0x8D,OLED_CMD); /*set charge pump disable*/ 
	OLED_WR_Byte(0x14,OLED_CMD);
	OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/

	printf("SSD1306 init \r\n");
}  

